﻿#include "TransmitCodec.h"

#include "TransmitRecord.h"
#include "MsgIdManager.h"
#include "RegisterCenter_Device.h"
#include "RegisterCenter_User.h"
#include "UdpCodec.h"
#include "TcpCodec.h"
#include "ScriptRunner.h"

TransmitCodec::TransmitCodec()
{
  setObjectName(getClassNameFirstLow<TransmitCodec>());
  tcpTypeToUdpTypeMap.insert(TcpCodec::MCUCtrl,UdpCodec::MCUCtrl);
  tcpTypeToUdpTypeMap.insert(TcpCodec::TurnTable,UdpCodec::TurnTable);
  udpTypeToTcpTypeMap.insert(UdpCodec::MCUCtrl,TcpCodec::MCUCtrl);
  udpTypeToTcpTypeMap.insert(UdpCodec::TurnTable,TcpCodec::TurnTable);
}

TransmitCodec::~TransmitCodec()
{
}

void TransmitCodec::decode_udp(uint deviceId, ushort msgId,uchar type, QByteArray data)
{
  //device数据包从设备端发送来，解析并视情况转发给客户端
  //暂时不需要返回值
  (void)type;
  (void)data;
  if (!dataRecordMap.contains(deviceId)) //如果数据记录中不包含对应deviceId，则不作处理
    {
      return;
    }
  TransmitRecord *dataRecord = dataRecordMap.value(deviceId);
  if (dataRecord->getMsgId() != msgId) //若msgId与数据记录中的msgId不一致，则不作处理
    {
      return;
    }
  dataRecord->getTimer()->stop(); //停止重发计时器
  uint userId = dataRecord->getUserId();
  removeDataRecord(deviceId);
  if(ScriptRunner::userId_scriptRunner==userId)
    {
      scriptRunner->handleTransmitResult(deviceId,Result::Succeed);
    }
  else if (registerCenter_User->isOnline(userId)) //如果客户端在线，转发回客户端
    {
      //data的第一个字节是mcu控制里的分类标识，是通用的，不需要mid可以直接发送
      //发送下发指令成功的反馈
      tcpCodec->code(userId, TcpCodec::Transmit, QByteArray().append(Result::Succeed));
    }
}

void TransmitCodec::decode_tcp(uint deviceId, uint userId, uchar type, QByteArray data)
{
  //user数据包从客户端端发送来，解析并视情况转发给设备端
  //1字节数据包类型
  //数据

  Result result;
  if (dataRecordMap.contains(deviceId))
    {
      result=Result::CantSend;
    }
  else if (!registerCenter_Device->isOnline(deviceId))//设备不在线
    {
      result=Result::Offline;
    }
  else if(!tcpTypeToUdpTypeMap.contains(type))//不存在对应的数据格式
    {
      result=Result::ErrorData;
    }
  else
    {
      ushort msgId = MsgIdManager::getMsgId();
      TransmitRecord *dataRecord = (new TransmitRecord)->setData(data)
                                                       ->setUserId(userId)
                                                       ->setMsgId(msgId)
                                                       ->setDeviceId(deviceId);
      QTimer *timer = dataRecord->getTimer();
      dataRecordMap.insert(deviceId, dataRecord);
      connect(timer, &QTimer::timeout, [=]() { repeatSendData(deviceId); });
      timer->start(10 * 1000);
      udpCodec->code(deviceId, msgId, tcpTypeToUdpTypeMap.value(type), data);
      result=Result::Sending;
    }
  if(ScriptRunner::userId_scriptRunner==userId)
    {
      scriptRunner->handleTransmitResult(deviceId,result);
    }
  else
    {
      tcpCodec->code(userId, TcpCodec::Transmit, QByteArray().append(result));
    }
}

bool TransmitCodec::isCanSendInstruction(unsigned int deviceId)
{
  return dataRecordMap.contains(deviceId);
}

void TransmitCodec::repeatSendData(uint deviceId)
{
  TransmitRecord *dataRecord = dataRecordMap.value(deviceId);
  if (!registerCenter_Device->isOnline(deviceId)) //如果设备离线了，则代表发送超时
    {
      uint userId = dataRecord->getUserId();
      removeDataRecord(deviceId);
      if (registerCenter_User->isOnline(userId))//若用户还在线则发送反馈
        {
          tcpCodec->code(userId, TcpCodec::Transmit, QByteArray().append(Result::TimeOut));
        }
    }
  else //设备在线则继续发送
    {
      udpCodec->code(deviceId, dataRecord->getMsgId(), UdpCodec::MCUCtrl, dataRecord->getData());
    }
}

void TransmitCodec::removeDataRecord(uint deviceId)
{
  if (dataRecordMap.contains(deviceId))
    {
      dataRecordMap.take(deviceId)->deleteLater();
      emit signal_sendReady(deviceId);
    }
}

RegisterCenter_Device *TransmitCodec::getRegisterCenter_Device() const
{
  return registerCenter_Device;
}

TransmitCodec *TransmitCodec::setRegisterCenter_Device(RegisterCenter_Device *const registerCenter_Device)
{
  this->registerCenter_Device = registerCenter_Device;
  printInjection(this, registerCenter_Device);
  return this;
}

RegisterCenter_User *TransmitCodec::getRegisterCenter_User() const
{
  return registerCenter_User;
}

TransmitCodec *TransmitCodec::setRegisterCenter_User(RegisterCenter_User *const registerCenter_User)
{
  this->registerCenter_User = registerCenter_User;
  printInjection(this, registerCenter_User);
  return this;
}

UdpCodec *TransmitCodec::getUdpCodec() const
{
  return udpCodec;
}

TransmitCodec *TransmitCodec::setUdpCodec(UdpCodec *const udpCodec)
{
  this->udpCodec = udpCodec;
  printInjection(this, udpCodec);
  return this;
}

TcpCodec *TransmitCodec::getTcpCodec() const
{
  return tcpCodec;
}

TransmitCodec *TransmitCodec::setTcpCodec(TcpCodec *const tcpCodec)
{
  this->tcpCodec = tcpCodec;
  printInjection(this, tcpCodec);
  return this;
}

ScriptRunner* TransmitCodec::getScriptRunner()const
{
  return scriptRunner;
}

TransmitCodec* TransmitCodec::setScriptRunner(ScriptRunner*const scriptRunner)
{
  this->scriptRunner=scriptRunner;
  printInjection(this,scriptRunner);
  return this;
}

void TransmitCodec::objectAutoInjection(QHash<QString, QObject *> *objMap)
{
  setRegisterCenter_Device(getObjFromMap<RegisterCenter_Device>(objMap));
  setRegisterCenter_User(getObjFromMap<RegisterCenter_User>(objMap));
  setUdpCodec(getObjFromMap<UdpCodec>(objMap));
  setTcpCodec(getObjFromMap<TcpCodec>(objMap));
  setScriptRunner(getObjFromMap<ScriptRunner>(objMap));
}
